package com.hospital.search.module.utils;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import com.hospital.common.pojo.TIndexRecord;
import com.hospital.search.module.base.ActiveType;
import com.hospital.search.module.exception.SearchServiceException;
import com.hospital.search.module.exception.enums.SearchServiceExpCode;
import com.hospital.search.module.service.TIndexRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDateTime;

@Component
public class PostIndexManager {
    @Value("${elastic.index-alias}")
    private String aliasName;
    @Autowired
    private TIndexRecordService indexRecordService;

    private final ElasticsearchClient esClient;
    private final Integer WITH_ALIAS = 0;
    private final Integer WITHOUT_ALIAS = 1;

    public PostIndexManager(ElasticsearchClient esClient) {
        this.esClient = esClient;
    }

    /**
     * 创建索引并绑定别名
     */
    public void createIndex(String indexName, Integer withAlias) {
        try {
            switch (withAlias){
                case 0->{
                    boolean exists = esClient.indices().exists(e -> e.index(indexName)).value();
                    if (!exists) {
                        esClient.indices().create(c -> c
                                .index(indexName)
                                .aliases(aliasName, a -> a.isWriteIndex(true))
                                .mappings(this.buildPostIndexMapping())
                        );
                    }
                }
                case 1->{
                    esClient.indices().create(c -> c
                            .index(indexName)
                            .mappings(this.buildPostIndexMapping())
                    );
                }
            }
            TIndexRecord indexRecord = new TIndexRecord();
            indexRecord.setIndexName(indexName);
            indexRecord.setAliasName(aliasName);
            indexRecord.setIsActive(ActiveType.ALIVE.value);
            indexRecord.setCreateTime(LocalDateTime.now());
            indexRecordService.insert(indexRecord);

        } catch (IOException e) {
            throw new RuntimeException("创建索引失败: " + indexName, e);
        }
    }

    /**
     * 索引是否存在
     */
    public Boolean indexExists(String indexName) {
        try {
            return esClient.indices().exists(e -> e.index(indexName)).value();
        } catch (IOException e) {
            throw new RuntimeException("查询索引是否存在失败: " + indexName, e);
        }
    }
    /**
     * 替换别名指向的新索引（原子切换）
     */
    public void switchAlias(String oldIndex, String newIndex) {
        try {
            createIndex(newIndex, WITHOUT_ALIAS);
            esClient.indices().updateAliases(a -> a
                    .actions(act -> act
                            .remove(r -> r.index(oldIndex).alias(aliasName))
                    ).actions(act -> act
                            .add(r -> r.index(newIndex).alias(aliasName).isWriteIndex(true)))
            );
            indexRecordService.update(oldIndex, ActiveType.DEAD);
            indexRecordService.update(newIndex, ActiveType.ALIVE);
        } catch (IOException e) {
            throw new SearchServiceException(SearchServiceExpCode.SWITCH_INDEX_ERROR);
        }
    }

    /**
     * 删除索引
     */
    public void deleteIndex(String indexName) {
        try {
            if(esClient.indices().exists(e -> e.index(indexName)).value()){
                esClient.indices().delete(d -> d.index(indexName));
            }
        } catch (IOException e) {
            throw new SearchServiceException(SearchServiceExpCode.DELETE_INDEX_ERROR);
        }
    }
    public void rollBackIndex(String oldIndex, String newIndex) {
        try {
            if(!indexExists(newIndex)){
                throw new SearchServiceException(SearchServiceExpCode.INDEX_NOT_EXISTS);
            }
            esClient.indices().updateAliases(a -> a
                    .actions(act -> act
                            .remove(r -> r.index(oldIndex).alias(aliasName))
                    ).actions(act -> act
                            .add(r -> r.index(newIndex).alias(aliasName).isWriteIndex(true)))
            );
            deleteIndex(oldIndex);
        } catch (IOException e) {
            throw new SearchServiceException(SearchServiceExpCode.ROLLBACK_INDEX_ERROR);
        }
    }
    /**
     * 构建字段映射
     */
    private TypeMapping buildPostIndexMapping() {
        return TypeMapping.of(m -> m
                .properties("metaId", p -> p.long_(l -> l))
                .properties("sectionId", p -> p.long_(l -> l))
                .properties("authorId", p -> p.long_(l -> l))
                .properties("title", p -> p.text(t -> t.analyzer("ik_max_word").searchAnalyzer("ik_smart")))
                .properties("abstracts", p -> p.text(t -> t.analyzer("ik_max_word").searchAnalyzer("ik_smart")))
                .properties("content", p -> p.text(t -> t.analyzer("ik_max_word").searchAnalyzer("ik_smart")))
                .properties("sectionName", p -> p.keyword(k -> k))
                .properties("isTop", p -> p.integer(i -> i))
                .properties("isPinned", p -> p.integer(i -> i))
                .properties("likeCount", p -> p.integer(i -> i))
                .properties("replyCount", p -> p.integer(i -> i))
                .properties("favoriteCount", p -> p.integer(i -> i))
                .properties("heatScore", p -> p.long_(l -> l))
                .properties("firstAttachmentUrl", p -> p.text(t -> t))
                .properties("createTime", p -> p.date(d -> d.format("epoch_millis")))
                .properties("updateTime", p -> p.date(d -> d.format("epoch_millis")))
                .properties("author",p->p.keyword(k->k))
                .properties("authorRole",p->p.integer(i->i))
        );
    }
}
